package org.brisling.base.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Query;

import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.task.Task;
import org.brisling.base.domain.ListDomain;
import org.brisling.base.domain.RetDomain;
import org.brisling.base.domain.inf.BaseFlowDomainInf;
import org.brisling.base.repository.BaseWorkflowRepository;
import org.brisling.common.util.LongUtil;
import org.brisling.workflow.domain.VOHistoric;
import org.brisling.workflow.service.WorkflowOperatorService;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

public class BaseFlowService<T extends BaseFlowDomainInf> extends BaseService<T>{
	
	@Autowired
	protected WorkflowOperatorService flowService;	
	
	protected BaseWorkflowRepository<T,Long> baseFlowRepo = null;	
	
	@Autowired
	protected void setFlowService(BaseWorkflowRepository<T,Long> baseFlowRepo){
		this.baseFlowRepo = baseFlowRepo;
		this.baseRepo = baseFlowRepo;
	}
	@SuppressWarnings("unused")
	private static Logger logger = LoggerFactory.getLogger(BaseFlowService.class); 
	
	
	/**
	 * 分页查询业务列表页面	 
	 * @param page
	 * @param rows
	 * @param sort
	 * @return
	 */
	
	protected ListDomain<T> getListDomain(
			Integer page,Integer rows,String sort,String fullBizcode){
		
		if((fullBizcode!=null) && (fullBizcode.trim().length()>0)){
			ListDomain<T> domain= new ListDomain<T>();
			List<T> entitys= this.getPagedFlowRows(page, rows, sort, fullBizcode);
			domain.setRows(entitys);
			domain.setTotal((long) entitys.size());
			return domain;
		}else
			return super.getPagedList(page, rows);
			
	}
	/**
	 * 分页查询流程业务列表
	 * @param page
	 * @param rows
	 * @param sort
	 * @return
	 */
	
	protected List<T> getPagedFlowRows(Integer page,Integer rows,String sort,String fullBizcode
			){
		
		if(page==null)
			page = 0;
		if(rows==null)
			rows = 10;
		
		List<T> baseFlowDomains = new ArrayList<T>();
		Map<String,Task> flowTasks=flowService.findRunningProcessInstaceIds(fullBizcode, page*rows,page*rows+rows);
		
		
		Set<String> ids =flowTasks.keySet();
		
		
		if(ids!=null&&ids.size()>0){
			baseFlowDomains = (List<T>) this.baseFlowRepo.findByFlowInstIds(ids);
		}
		
		if((baseFlowDomains!=null)&&(baseFlowDomains.size()>0)){
			for(T domain:baseFlowDomains){
				domain.setFlowState(flowTasks.get(domain.getFlowInstId()).getName());
				domain.setFlowTaskId(flowTasks.get(domain.getFlowInstId()).getId());
			}
		}
		return baseFlowDomains;			
	}
	
	/**
	 * 分页查询流程业务列表
	 * @param page
	 * @param rows
	 * @param sort
	 * @return
	 */
	
	
	protected ListDomain<T> getPagedFinishedFlowRows(Integer page,Integer rows,String sort,String fullBizcode
			){
		
		if(page==null)
			page = 0;
		if(rows==null)
			rows = 10;
		
		ListDomain<T> baseFlowDomains = new ListDomain<T>();
		List<T> baseFlows = new ArrayList<T>();
		Map<String,HistoricProcessInstance> flowTasks=flowService.findFinishedProcessInstaces(fullBizcode, this.getPageParam(page, rows) );
			
		Set<String> ids =flowTasks.keySet();
		if(ids!=null&&ids.size()>0){
			baseFlows = (List<T>) this.baseFlowRepo.findByFlowInstIds(ids);
		}
		if(baseFlows!=null&&baseFlows.size()>0){
			
			baseFlowDomains.setTotal(new Long(baseFlows.size()));
			baseFlowDomains.setRows(baseFlows) ;
		}else{
			baseFlowDomains.setTotal(0l);
			baseFlowDomains.setRows(new ArrayList<T>()) ;
		}
			
			
		
		return baseFlowDomains;			
	}
	
	/**
	 * 获取当前用户需处理的业务实例
	 * @param page
	 * @param rows
	 * @param groupIds
	 * @param userIds
	 * @param condition
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List getPagedUserTaskList(int page,int rows,String groupIds,String userIds,String businessKey,HashMap<String,Object> condition){
		
		
		String bizTableName =this.getTableName(clazz);

		String taskTableName="act_ru_execution";
		String sqlString = " SELECT b.* FROM " + bizTableName +" b LEFT JOIN " +
				taskTableName + " t ON b.flowInstId = t.id_ ";
		Query query = entityManager.createNativeQuery(sqlString);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		Integer[] pageParam = this.getPageParam(page, rows);
		return query.setFirstResult(pageParam[0])
				.setMaxResults(pageParam[1])
				.getResultList();
	}
	
	/**
	 * 保存缺陷记录
	 * @param id
	 */
	
	protected T saveFlowEntity(String userid,T obj){
				
		if((obj.getFlowid()==null)||(obj.getFlowInstId()==null)||(obj.getFlowInstId().trim().length()<=0)){
			//流程定义id不为空，流程实例id为空			
			return this.saveFlowEntity(userid,obj, true);
		}else
			return this.saveFlowEntity(userid,obj, false);
	}	
	/**
	 * 
	 * @param T 业务实体
	 * @param isFlowEnable
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected T saveFlowEntity(String userid,T t,boolean isFlowEnable){
		if(isFlowEnable){
			
			HashMap<String,Object> variables = new HashMap<String,Object>();
			t = (T) flowService.startWorkflowByDefinitionId(userid,t.getFlowid(), t.getFullBizcode(), variables, t);
			
		}
		return super.save(t);
	} 	
	
	/**
	 * 获取业务实体记录及流程执行记录
	 * @param id 业务表单唯一编码
	 * @return T 包含流程执行信息的业务实体类
	 */
	protected List<VOHistoric> getHistoricById(Long id){
		
		List<VOHistoric> historics = null;
		if(id!=null){
			T entity = super.getOne(id);
			
			//判断业务实体是否为空
			if((entity!=null) && (entity.getFlowInstId()!=null)){
				
				String procInstId = entity.getFlowInstId();
				
				historics=flowService.findHistoricProcessInfo(procInstId);
			}
		}
		
		return historics;
	}
	
	/**
	 * 获取业务实体的流程执行记录
	 * @param procInstId 业务表单流程实例唯一编码
	 * @return List<HistoricTaskInstance> 流程执行信息
	 */
	protected List<VOHistoric> getHistoricByProcInstId(String procInstId){
		
		List<VOHistoric> historics = null;
		if(procInstId!=null){				
			historics=flowService.findHistoricProcessInfo(procInstId);
		}		
		return historics;
	}
	
	/**
	 * 获取业务实体的流程执行记录
	 * @param procInstId 业务表单流程实例唯一编码
	 * @return List<HistoricTaskInstance> 流程执行信息
	 */
	protected ListDomain<VOHistoric> getHistoricListDomainByProcInstId(String procInstId){
		
		ListDomain<VOHistoric> listdomain = new ListDomain<VOHistoric>();
		if(procInstId!=null){				
			List<VOHistoric> historics=flowService.findHistoricProcessInfo(procInstId);
			if((historics!=null) &&(historics.size()>0)){
				listdomain.setRows(historics);
				listdomain.setTotal((long) historics.size());
			}
		}		
		return listdomain;
	}
	
	/**
	 * 保存签收意见
	 * @param userid	用户编码
	 * @param instId	流程实例编码
	 * @param signInfo	签收意见
	 * @return	java.util.String	签收是否成功标志
	 */
	protected String saveSignInfo(String userid,String flowInstId,String flowTaskId,String signInfo){
		return flowService.saveSignTask(userid, flowInstId,flowTaskId, signInfo);
	}
	
	/**
	 * 保存签收意见
	 * @param userid	用户编码
	 * @param instId	流程实例编码
	 * @param signInfo	签收意见
	 * @return	java.util.String	签收是否成功标志
	 */
	protected ListDomain<Object> saveSignInfo(String userid,String body){
		ListDomain<Object> domains = null;
		Map<String,Object> paramMap = this.getBodyParam(body);
		if(paramMap !=null){
			if(paramMap.containsKey("flowInstId") && paramMap.containsKey("flowTaskId") && paramMap.containsKey("signInfo")){
				String ret = this.saveSignInfo(userid, 
						paramMap.get("flowInstId").toString(),
						paramMap.get("flowTaskId").toString(), 
						paramMap.get("signInfo").toString());
				if(ret.compareTo("200")!=0){
					domains = new ListDomain<Object>("error");
					domains.setMsg(ret);
					return domains;
				}else{
					return new ListDomain<Object>();
				}
			}
		}
		domains = new ListDomain<Object>("error");
		domains.setMsg("发生系统错误。请联系系统管理员处理");
		return domains;
	}
	
	/**
	 * 任务执行
	 * @param taskid
	 * @param signInfo
	 * @param userid
	 * @return java.lang.String 任务执行状态	
	 */
	protected String saveTaskComplete(String userid,String flowInstId,String taskid,String signInfo){
		return flowService.saveTaskComplete(userid,flowInstId,taskid, signInfo,null);
	}
	
	/**
	 * 任务执行
	 * @param taskid
	 * @param signInfo
	 * @param userid
	 * @return java.lang.String 任务执行状态	
	 */
	protected String saveTaskComplete(String userid,String flowInstId,String taskid,String signInfo,Map<String,Object> variables){
		return flowService.saveTaskComplete(userid,flowInstId,taskid, signInfo,variables);
	}
	
	/**
	 * 任务执行
	 * @param taskid
	 * @param signInfo
	 * @param userid
	 * @return java.lang.String 任务执行状态	
	 */
	protected String saveTaskCompleteAndCandidate(String userid,String flowInstId,String taskid,String signInfo){
		return flowService.saveTaskComplete(userid,flowInstId,taskid, signInfo,null);
	}
	
	/**
	 * 任务执行
	 * @param taskid
	 * @param signInfo
	 * @param userid
	 * @return java.lang.String 任务执行状态	
	 */
	protected String saveTaskCompleteAndCandidate(String userid,String flowInstId,String taskid,String signInfo,Map<String,Object> variables){
		return flowService.saveTaskComplete(userid,flowInstId,taskid, signInfo,variables);
	}
	
	/**
	 * 任务执行并对下一节点人员授权
	 * @param userid
	 * @param domain
	 * @param signInfo
	 * @return
	 */
	protected String completeTaskAndCandidateByEntity(String userid,BaseFlowDomainInf domain,String signInfo){
		
		return flowService.completeTaskAndCandidate(userid,domain, signInfo);
	}
	
	/**
	 * 任务执行并对下一节点人员授权
	 * @param userid
	 * @param domain
	 * @param signInfo
	 * @return
	 */
	protected String completeTaskAndCandidateByEntity(String userid,BaseFlowDomainInf domain,String signInfo,Map<String,Object> variables){
		
		return flowService.completeTaskAndCandidate(userid,domain, signInfo,variables);
	}
	
	/**
	 * 流程节点回退
	 * @param userid
	 * @param domain
	 * @param backNodeKey
	 * @param signInfo
	 * @return
	 */
	protected RetDomain saveSendBack(String userid,BaseFlowDomainInf domain,String backNodeKey, String signInfo){
		
		return flowService.saveSendBack(userid,domain, backNodeKey,  signInfo);
	}
	
	/**
	 * 任务执行并对下一节点人员授权
	 * @param userid
	 * @param domain
	 * @param signInfo
	 * @return
	 */
	protected String completeTaskAndCandidateById(String userid,String flowInstId,String signInfo){
		BaseFlowDomainInf domain =baseFlowRepo.findByFlowInstId(flowInstId);
		return this.completeTaskAndCandidateByEntity(userid,domain, signInfo);
	}
	
	/**
	 * 删除工作流实例及业务实体
	 * @param t			业务对象实例
	 * @param reason	删除原因
	 * @return
	 */
	protected Boolean deleteTask(T t,String reason){
		
		if(t.getId()==null)			
			return false;
		
		if(t.getFlowInstId()==null ||t.getFlowInstId().trim().length()<=0){
			return false;
		}
		if(flowService.deleteProcessInstance(t.getFlowInstId(), reason)){
			baseRepo.delete(t.getId());
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * 删除工作流实例及业务实体
	 * @param id	业务实体id
	 * @param reason	删除原因
	 * @return
	 */
	protected Boolean deleteTask(Long id,String reason){
		T t = null;
		if(id!=null){
			t = this.getOne(id); 
			return deleteTask(t,reason);
		}
		
		return false;
		
	}
	
	/**
	 * 删除工作流实例及业务实体
	 * @param id			业务实体id
	 * @param procInstId	流程id
	 * @param reason		删除原因
	 * @return
	 */
	protected Boolean deleteTask(Long id,String procInstId,String reason){
		
		if(id==null || id.longValue()<=0){
			return false;
		}
		
		if(procInstId==null ||procInstId.trim().length()<=0){
			return false;
		}
		if(flowService.deleteProcessInstance(procInstId, reason)){
			baseRepo.delete(id);
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * 删除工作流实例及业务实体集合
	 * @param id	业务实体id
	 * @param ids	待删除业务实体id集合
	 * @param reason	删除原因
	 * @return
	 */
	protected Integer deleteTaskList(String ids,String reason){
		
		//定义返回变量
		Integer retCount = 0;
		
		//定义临时变量
		T t = null;
		
		//定义id集合数组临时变量
		String[] idArray = null;
		
		//判断传入参数是否为空
		if(ids!=null){
			
			//不为空，解析id集合为数组
			idArray = ids.split(",");
			
			//判断待删除task id集合是否为空
			if(idArray!=null && idArray.length>0){
				
				//循环迭代id数组
				for(String _id:idArray){
					
					//判断id值是否为空
					if(_id!=null){
						
						//不为空，转换为Long类型
						Long _lid = LongUtil.getLongValue(_id, null);
						
						//判断转换后Long 类型id值是否为空
						if(_lid!=null) {
							
							//查询业务记录是否存在
							t = this.getOne(_lid); 
							
							//判断查询结果是否存在
							if(t!=null && t.getFlowInstId()!=null && (t.getFlowInstId().trim().length()>0)){
								
								//删除流程业务及数据
								deleteTask(t,reason);
								
								//返回计数器加1
								retCount +=1;
							}
						}
					}
				}				
			}
		}
		
		return retCount;
		
	}
	
	/**
	 * 删除流程记录
	 * @param id	单条流程记录id
	 * @param ids	多条流程记录id集合
	 * @return
	 */
	public RetDomain delFlowRow(@RequestParam(value="id",required=false) Long id,@RequestParam(value="ids",required=false) String ids){
		RetDomain domain = new RetDomain();
		if(id!=null){
			if(deleteTask(id, null)){
				domain.setSuccessMsg("200");
				return domain;
			}else{
				domain.setErrorMsg("500");
				return domain;
			}
		}else{
			if(ids!=null){
				Integer count =deleteTaskList(ids, null);
				domain.setMsg("删除 " + count + " 条记录成功!");
			}
		}
		
		return domain;
		
	}

}
